package com.newasia.server.common.template;

import com.newasia.server.common.template.dataItem.ProtocolFormat;
import com.newasia.server.common.template.dataItem.basics.Activ;
import com.newasia.server.common.template.dataItem.basics.DataShow;
import com.newasia.server.common.template.dataItem.basics.DataType;
import com.newasia.server.common.template.dataItem.basics.StartStop;
import com.newasia.server.common.tool.CheckObjectIsNullUtils;
import jodd.util.StringUtil;

import javax.tools.JavaCompiler;
import javax.tools.StandardJavaFileManager;
import javax.tools.ToolProvider;
import java.io.File;
import java.io.FileWriter;
import java.lang.reflect.Constructor;
import java.lang.reflect.Method;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

import static com.newasia.server.common.tool.CheckObjectIsNullUtils.checkObjIsNull;

/**
 * @author LiChong
 * @description 生成解析模板的工具
 * @date 2020/4/21
 */

public class AnalysisTemplateTool {

    private static final String ln = "\r\n";

    public static Object newInstance(AnalysisTemplateClassLoader classLoader, ProtocolFormat protocolFormat){
        try {

            Long moduleId = protocolFormat.getName().getName();
            //0.检验文件是否存在
            String filePath = AnalysisTemplateTool.class.getResource("").getPath();
            //System.out.println(filePath);
            File f = new File(filePath +"ModuleAnalysisTemplate$NA" + moduleId + ".class");
            if(!f.exists()){
                //1、动态生成源代码.java文件
                String src = generateSrc(protocolFormat);

                //System.out.println(src);
                //System.out.println(filePath);
                //2、Java文件输出磁盘
                f = new File(filePath +"ModuleAnalysisTemplate$NA" + moduleId + ".java");
                FileWriter fw = new FileWriter(f);
                fw.write(src);
                fw.flush();
                fw.close();

                //3、把生成的.java文件编译成.class文件
                JavaCompiler compiler = ToolProvider.getSystemJavaCompiler();
                StandardJavaFileManager manage = compiler.getStandardFileManager(null,null,null);
                Iterable iterable = manage.getJavaFileObjects(f);

                JavaCompiler.CompilationTask task = compiler.getTask(null,manage,null,null,null,iterable);
                task.call();
                manage.close();
            }
            //4、编译生成的.class文件加载到JVM中来
            Class proxyClass =  classLoader.findClass("ModuleAnalysisTemplate$NA" + moduleId);
            Constructor c = proxyClass.getConstructor();
            f.delete();

            //5、返回字节码重组以后的新的代理对象
            return c.newInstance();
        }catch (Exception e){
            e.printStackTrace();
        }
        return null;
    }

    private static String generateSrc(ProtocolFormat protocolFormat){
        StringBuffer sb = new StringBuffer();
        sb.append(AnalysisTemplateTool.class.getPackage() + ";" + ln);
        sb.append("import com.newasia.server.common.template.dataItem.basics.CurrentStatus;" + ln);
        sb.append("import com.newasia.server.common.template.dataItem.basics.DataType;" + ln);
        sb.append("import com.newasia.server.common.template.dataItem.basics.WiFi;" + ln);
        sb.append("import com.newasia.server.common.tool.CheckObjectIsNullUtils;" + ln);
        sb.append("import jodd.util.StringUtil;" + ln);
        sb.append("import java.util.*;" + ln);

        sb.append("public class ModuleAnalysisTemplate$NA" + protocolFormat.getName().getName() + " extends ModuleAnalysisTemplate {" + ln);

        Integer dbShowId = 1;
        if(isExistDbShow(protocolFormat)){
            dbShowId = getDbShowId(protocolFormat);
        }
        sb.append("@Override" + ln);
        sb.append("public DataType getShowData() {" + ln);
        sb.append("Integer dbShowId = "+dbShowId+";"+ln);
        sb.append("DataType temperature = protocolFormat.getDataList().get(dbShowId-1);"+ln);
        sb.append("temperature.setValue(data.getDb"+dbShowId+"());" + ln);
        sb.append("return temperature;"+ln);
        sb.append("}" + ln);

        sb.append("@Override" + ln);
        sb.append("public CurrentStatus getCurrentStatus() {" + ln);
        sb.append("CurrentStatus currentStatus = new CurrentStatus();" + ln);
        if(isExistDbStartStop(protocolFormat)) {
            Integer startStopId = getDbStartStopId(protocolFormat);
            sb.append("Integer startStopId = " + startStopId + ";" + ln);
            sb.append("DataType startStop = protocolFormat.getDataList().get(" + startStopId + " - 1);" + ln);
            sb.append("Integer value = data.getDb" + startStopId + "();" + ln);
            sb.append("startStop.setValue(value);" + ln);
            sb.append("currentStatus.setStateFlag(value);" + ln);
            sb.append("currentStatus.setState(startStop.getValue());" + ln);
        }else {
            sb.append("currentStatus.setStateFlag(0);" + ln);
            sb.append("Map<String, Object> map = new HashMap<String, Object>();" + ln);
            sb.append("map.put(\"key\", 0);" + ln);
            sb.append("map.put(\"value\", \"在线\");" + ln);
            sb.append("currentStatus.setState(map);" + ln);
        }
        sb.append("return currentStatus;" + ln);
        sb.append("}" + ln);

        sb.append("@Override" + ln);
        sb.append("public boolean isWiFi(){" + ln);
        sb.append("WiFi wiFi = protocolFormat.getWiFi();" + ln);
        sb.append("if(!CheckObjectIsNullUtils.checkObjIsNull(wiFi)&&wiFi.getWifi()==1){" + ln);
        sb.append("return true;" + ln);
        sb.append("}" + ln);
        sb.append("return false;" + ln);
        sb.append("}" + ln);

        sb.append("@Override" + ln);
        sb.append("public List<DataType> getBootOptions(){" + ln);
        //若无设置项，则无法获取设置参数
        sb.append("if (!data.getHasSetList()){" + ln);
        sb.append("return null;" + ln);
        sb.append("}" + ln);
        sb.append("List<DataType> bootOptions = new ArrayList<DataType>();" + ln);
        if(isExistDbStartStopSetUp(protocolFormat)){
            List<Integer> ids = getDbStartStopSetUpIds(protocolFormat);
            for (int i = 1;i<=ids.size();i++){
                int id = ids.get(i-1);
                sb.append("Integer optionId"+i+" = "+id+";"+ln);
                sb.append("DataType bootOption"+i+" = protocolFormat.getSetupList().get(optionId"+i+"-1);"+ln);
                sb.append("bootOption"+i+".setValue(data.getSet"+id+"());" + ln);
                sb.append("bootOptions.add(bootOption"+i+");" + ln);
            }
        }
        sb.append("return bootOptions;" + ln);
        sb.append("}" + ln);

        sb.append("@Override" + ln);
        sb.append("public boolean isMaintain(){" + ln);
        if(isExistisMaintain(protocolFormat)){
            sb.append("return true;" + ln);
        }else{
            sb.append("return false;" + ln);
        }
        sb.append("}" + ln);

        sb.append("@Override" + ln);
        sb.append("public boolean isActivation(){" + ln);
        Integer activationId = getActivationId(protocolFormat);
        sb.append("if (!data.getHasSetList()){" + ln);
        sb.append("return true;" + ln);
        sb.append("}" + ln);
        if(activationId==0){
            sb.append("return true;" + ln);
        }else{
            sb.append("Integer activationId = "+activationId+";"+ln);
            sb.append("String pwPass = data.getPwPass();" + ln);
            sb.append("String activation = data.getSet"+activationId+"().toString();" + ln);
            sb.append("if(StringUtil.equals(pwPass,activation)){" + ln);
            sb.append("return true;" + ln);
            sb.append("}" + ln);
            sb.append("return false;" + ln);
        }
        sb.append("}" + ln);

        sb.append("@Override" + ln);
        sb.append("public DataType countDoorOpenTotalTime() {" + ln);
        Integer doorOpenTotalId = getDoorOpenTotalId(protocolFormat);
        if(doorOpenTotalId == 0){
            sb.append("return null;"+ln);
        }else{
            sb.append("Integer doorOpenTotalId = "+doorOpenTotalId+";"+ln);
            sb.append("DataType doorOpenTotal = protocolFormat.getDataList().get(doorOpenTotalId-1);"+ln);
            sb.append("doorOpenTotal.setValue(data.getDb"+doorOpenTotalId+"());" + ln);
            sb.append("return doorOpenTotal;"+ln);
        }
        sb.append("}" + ln);

        sb.append("@Override" + ln);
        sb.append("public DataType countDoorOpenMonthTime() {" + ln);
        Integer doorOpenMonthId = getDoorOpenMonthId(protocolFormat);
        if(doorOpenTotalId == 0){
            sb.append("return null;"+ln);
        }else{
            sb.append("Integer doorOpenMonthId = "+doorOpenMonthId+";"+ln);
            sb.append("DataType doorOpenMonth = protocolFormat.getDataList().get(doorOpenMonthId-1);"+ln);
            sb.append("doorOpenMonth.setValue(data.getDb"+doorOpenMonthId+"());" + ln);
            sb.append("return doorOpenMonth;"+ln);
        }
        sb.append("}" + ln);

        sb.append("@Override" + ln);
        sb.append("public DataType getDefrosterElectricity() {" + ln);
        Integer defrosterElectricityId = getDefrosterElectricityId(protocolFormat);
        if(defrosterElectricityId == 0){
            sb.append("return null;"+ln);
        }else{
            sb.append("Integer defrosterElectricityId = "+defrosterElectricityId+";"+ln);
            sb.append("DataType defrosterElectricity = protocolFormat.getDataList().get(defrosterElectricityId-1);"+ln);
            sb.append("defrosterElectricity.setValue(data.getDb"+defrosterElectricityId+"());" + ln);
            sb.append("return defrosterElectricity;"+ln);
        }
        sb.append("}" + ln);

        sb.append("@Override" + ln);
        sb.append("public DataType getRefrigerationElectricity() {" + ln);
        Integer refrigerationElectricityId = getRefrigerationElectricityId(protocolFormat);
        if(refrigerationElectricityId == 0){
            sb.append("return null;"+ln);
        }else{
            sb.append("Integer refrigerationElectricityId = "+refrigerationElectricityId+";"+ln);
            sb.append("DataType refrigerationElectricity = protocolFormat.getDataList().get(refrigerationElectricityId-1);"+ln);
            sb.append("refrigerationElectricity.setValue(data.getDb"+refrigerationElectricityId+"());" + ln);
            sb.append("return refrigerationElectricity;"+ln);
        }
        sb.append("}" + ln);

        sb.append("}" + ln);
        return sb.toString();
    }

    /**
     *获取化霜电量id
     * @author LiChong
     * @date 2020/5/21
     * @param  * @param protocolFormat
     * @return boolean
     */
    private static Integer getDefrosterElectricityId(ProtocolFormat protocolFormat) {
        List<DataType> dataTypes = protocolFormat.getDataList();
        for (DataType dataType:dataTypes){
            if(StringUtil.equals(dataType.getName(),"化霜总电量")){
                if(dataType.getIsShow()==1){
                    return dataType.getId();
                }
            }
        }
        return 0;
    }

    /**
     *获取制冷电量id
     * @author LiChong
     * @date 2020/5/21
     * @param  * @param protocolFormat
     * @return boolean
     */
    private static Integer getRefrigerationElectricityId(ProtocolFormat protocolFormat) {
        List<DataType> dataTypes = protocolFormat.getDataList();
        for (DataType dataType:dataTypes){
            if(StringUtil.equals(dataType.getName(),"制冷总电量")){
                if(dataType.getIsShow()==1){
                    return dataType.getId();
                }
            }
        }
        return 0;
    }

    /**
     *获取总开门次数id
     * @author LiChong
     * @date 2020/5/21
     * @param  * @param protocolFormat
     * @return boolean
     */
    private static Integer getDoorOpenTotalId(ProtocolFormat protocolFormat) {
        List<DataType> dataTypes = protocolFormat.getDataList();
        for (DataType dataType:dataTypes){
            if(StringUtil.equals(dataType.getName(),"总开门次数")){
                if(dataType.getIsShow()==1){
                    return dataType.getId();
                }
            }
        }
        return 0;
    }

    /**
     *获取当月开门次数id
     * @author LiChong
     * @date 2020/5/21
     * @param  * @param protocolFormat
     * @return boolean
     */
    private static Integer getDoorOpenMonthId(ProtocolFormat protocolFormat) {
        List<DataType> dataTypes = protocolFormat.getDataList();
        for (DataType dataType:dataTypes){
            if(StringUtil.equals(dataType.getName(),"当月开门次数")){
                if(dataType.getIsShow()==1){
                    return dataType.getId();
                }
            }
        }
        return 0;
    }

    /**
     *判断是否存在保养项目
     * @author LiChong
     * @date 2020/5/21
     * @param  * @param protocolFormat
     * @return boolean
     */
    private static boolean isExistisMaintain(ProtocolFormat protocolFormat) {
        List<DataType> dataTypes = protocolFormat.getDataList();
        for (DataType dataType:dataTypes){
            if(dataType.getGroupId() == 80){
                return true;
            }
        }
        return false;
    }

    /**
     *系统状态
     * @author LiChong
     * @date 2020/5/20
     * @param  * @param protocolFormat
     * @return boolean
     */
    private static boolean isExistDbStartStop(ProtocolFormat protocolFormat) {
        StartStop dbStartStop = protocolFormat.getStartStop();
        if(dbStartStop==null||dbStartStop.getDbStartStopIdList().size()==0)
            return false;
        return true;
    }

    private static Integer getDbStartStopId(ProtocolFormat protocolFormat) {
        return protocolFormat.getStartStop().getDbStartStopIdList().get(0);
    }

    /**
     *显示数据组
     * @author LiChong
     * @date 2020/5/20
     * @param  * @param protocolFormat
     * @return boolean
     */
    private static boolean isExistDbShow(ProtocolFormat protocolFormat){
        DataShow dataShow = protocolFormat.getDataShow();
        if(dataShow==null||dataShow.getDbShowIdList().size()==0)
            return false;
        return true;
    }

    private static Integer getDbShowId(ProtocolFormat protocolFormat){
        return protocolFormat.getDataShow().getDbShowIdList().get(0);
    }

    private static List<Integer> getDbShowIds(ProtocolFormat protocolFormat){
        return protocolFormat.getDataShow().getDbShowIdList();
    }

    /**
     *开关机显示组
     * @author LiChong
     * @date 2020/5/20
     * @param  * @param protocolFormat
     * @return boolean
     */
    private static boolean isExistDbStartStopSetUp(ProtocolFormat protocolFormat) {
        StartStop dbStartStop = protocolFormat.getStartStop();
        if(dbStartStop==null||dbStartStop.getDbStartStopIdList().size()==0)
            return false;
        return true;
    }

    private static List<Integer> getDbStartStopSetUpIds(ProtocolFormat protocolFormat) {
        return protocolFormat.getStartStopSetup().getSetupStartStopIdList();
    }

    /**
     *获取激活码对应setupid
     * @author LiChong
     * @date 2020/5/21
     * @param  * @param protocolFormat
     * @return java.lang.Integer
     */
    private static Integer getActivationId(ProtocolFormat protocolFormat) {
        Activ activ = protocolFormat.getActiv();
        if(!checkObjIsNull(activ)){
            Integer activationId = activ.getActiv();
            if(activationId!=null){
                return activationId;
            }
        }
        return 0;
    }
}
